package com.ruoyi.caiwu.service.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

import com.ruoyi.caiwu.controller.SubjectBalanceController;
import com.ruoyi.caiwu.domain.AccountBookGeneral;
import com.ruoyi.caiwu.domain.AccountingSubjects;
import com.ruoyi.caiwu.mapper.AccountBookGeneralMapper;
import com.ruoyi.caiwu.mapper.AccountingSubjectsMapper;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.model.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.ruoyi.caiwu.mapper.AccountingVoucherMapper;
import com.ruoyi.caiwu.domain.AccountingVoucher;
import com.ruoyi.caiwu.service.IAccountingVoucherService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 凭证管理Service业务层处理
 *
 * @author ruoyi
 * @date 2025-02-25
 */
@Slf4j
@Service
public class AccountingVoucherServiceImpl implements IAccountingVoucherService
{
    @Autowired
    private AccountingVoucherMapper accountingVoucherMapper;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    AccountBookGeneralMapper accountBookGeneralMapper;

    @Autowired
    AccountingSubjectsMapper subjectsMapper;

    @Autowired
    private SubjectBalanceController subjectBalanceController;


    /**
     * 查询凭证管理
     *
     * @param voucherId 凭证管理主键
     * @return 凭证管理
     */
    @Override
    public AccountingVoucher selectAccountingVoucherByVoucherId(Long voucherId)
    {
        return accountingVoucherMapper.selectAccountingVoucherByVoucherId(voucherId);
    }

    /**
     * 查询凭证管理列表
     *
     * @param accountingVoucher 凭证管理
     * @return 凭证管理
     */
    @Override
    public List<AccountingVoucher> selectAccountingVoucherList(AccountingVoucher accountingVoucher)
    {
        LoginUser loginUser = tokenService.getLoginUser(SecurityUtils.getToken());
        Long userId = loginUser.getUserid();
        String userName = stringRedisTemplate.opsForValue().get("user:" + userId);
        accountingVoucher.setRemark(userName);
        return accountingVoucherMapper.selectAccountingVoucherList(accountingVoucher);
    }

    /**
     * 新增凭证管理
     *
     * @param accountingVoucher 凭证管理
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertAccountingVoucher(AccountingVoucher accountingVoucher) {
        //保存凭证到数据库
        int voucher = accountingVoucherMapper.insertAccountingVoucher(accountingVoucher);
        if (voucher > 0) {
            //更新或插入总账记录
            updateGeneralLedger(accountingVoucher);
            subjectBalanceController.insertSubjectBalance(accountingVoucher.getVoucherDate(), accountingVoucher.getSubjectId());
        }
        return voucher;
    }

    // 更新或插入总账记录，获得需要的数据
    private void updateGeneralLedger(AccountingVoucher voucher) {
        Long subjectId = voucher.getSubjectId();
        AccountingSubjects accountingSubjects = subjectsMapper.findById(subjectId);

        String subjectCode = accountingSubjects.getSubjectCode();
        System.err.println("subjectCode:" + subjectCode);
        String subjectName = accountingSubjects.getSubjectName();
        BigDecimal debitAmount = voucher.getDebitAmount();
        BigDecimal creditAmount = voucher.getCreditAmount();

        Date voucherDate = voucher.getVoucherDate();
        String period = getPeriodFromVoucherDate(voucherDate);
        System.err.println("period:" + period);

        // 通过科目编号和会计期间查找当前期间的总账记录
        HashMap<String, String> params = new HashMap<>();
        params.put("subjectCode", subjectCode);
        params.put("period", period);
        List<AccountBookGeneral> generalLedgers = accountBookGeneralMapper.findGeneralLedgerBySubjectCodeAndPeriod(params);
        if (!generalLedgers.isEmpty()) {
            updateExistingGeneralLedger(generalLedgers.get(0), debitAmount, creditAmount);
        } else {
            createNewGeneralLedgerEntry(subjectCode,subjectName, period, debitAmount, creditAmount);
        }

    }

    private void updateExistingGeneralLedger(AccountBookGeneral gl, BigDecimal debitAmount, BigDecimal creditAmount) {
        gl.setDebitAmount(gl.getDebitAmount().add(debitAmount));
        gl.setCreditAmount(gl.getCreditAmount().add(creditAmount));
        //计算更新后的余额
        gl.setBalance(calculateBalance(gl));

        accountBookGeneralMapper.insertGeneralLedger(gl); // 更新现有记录
    }



    //创建本期合计记录/本年累计记录，并设置借方金额和贷方金额。
    private AccountBookGeneral createGeneralLedgerBase(String subjectCode, String subjectName, String period, String summary) {
        AccountBookGeneral gl = new AccountBookGeneral();
        gl.setSubjectCode(subjectCode);
        gl.setSubjectName(subjectName);
        gl.setPeriod(period);
        gl.setSummary(summary);
        return gl;
    }

    //计算余额并设置余额方向（借、贷、平）
    private void setupBalanceAndDirection(AccountBookGeneral gl, BigDecimal debitAmount, BigDecimal creditAmount) {
//        BigDecimal decimal = calculateBalance(gl);
        gl.setBalance(calculateBalance(gl));
        int balanceComparison = gl.getBalance().compareTo(BigDecimal.ZERO);
        gl.setDirection(balanceComparison > 0 ? "借" : (balanceComparison < 0 ? "贷" : "平"));
    }

    //创建总账记录
    private void createNewGeneralLedgerEntry(String subjectCode, String subjectName, String period, BigDecimal debitAmount, BigDecimal creditAmount) {
        System.out.println("Entering createNewGeneralLedgerEntry method");
        // 初始化期初余额记录
        AccountBookGeneral openBookGeneral = createInitialBalanceRecord(subjectCode, subjectName, period);

        // 初始化本期合计记录
        AccountBookGeneral periodTotal = createGeneralLedgerBase(subjectCode, subjectName, period, "本期合计");
        periodTotal.setDebitAmount(debitAmount);
        periodTotal.setCreditAmount(creditAmount);
        setupBalanceAndDirection(periodTotal, debitAmount, creditAmount);//计算余额并计算余额方向
        System.err.println("总账"+openBookGeneral);

        String summary = periodTotal.getSummary();
        HashMap<String, String> map = new HashMap<>();
        map.put("subjectCode", subjectCode);
        map.put("period", period);
        map.put("summary", summary);

        // 获取从年初到当前期间的所有交易的借方和贷方总额
        BigDecimal yearToDateDebitTotal = accountBookGeneralMapper.findYearToDateDebitTotal(map);
        BigDecimal yearToDateCreditTotal = accountBookGeneralMapper.findYearToDateCreditTotal(map);

        // 初始化本年累计记录
        AccountBookGeneral yearToDateTotal = createGeneralLedgerBase(subjectCode, subjectName, period, "本年累计");
        yearToDateTotal.setDebitAmount(yearToDateDebitTotal);
        yearToDateTotal.setCreditAmount(yearToDateCreditTotal);
        setupBalanceAndDirection(yearToDateTotal, yearToDateDebitTotal, yearToDateCreditTotal);//计算余额并计算余额方向

        accountBookGeneralMapper.insertGeneralLedger(openBookGeneral);
        accountBookGeneralMapper.insertGeneralLedger(periodTotal);
        accountBookGeneralMapper.insertGeneralLedger(yearToDateTotal);
    }

    //创建期初余额记录
    private AccountBookGeneral createInitialBalanceRecord(String subjectCode, String subjectName, String period) {
        AccountBookGeneral gl = createGeneralLedgerBase(subjectCode, subjectName, period, "期初余额");
        gl.setDebitAmount(BigDecimal.ZERO);
        gl.setCreditAmount(BigDecimal.ZERO);
        //获取前一个会计期间的期末余额
        BigDecimal balance = getPreviousPeriodClosingBalance(subjectCode, period);
        if(balance==null){
            balance = BigDecimal.ZERO;
        }
        gl.setBalance(balance);
        int compareResult = gl.getBalance().compareTo(BigDecimal.ZERO);
        gl.setDirection(compareResult > 0 ? "借" : (compareResult < 0 ? "贷" : "平"));
        return gl;
    }

    //获取余额
    public BigDecimal calculateBalance(AccountBookGeneral gl) {
        // 检查 gl 是否为 null
        Objects.requireNonNull(gl, "AccountBookGeneral 对象不能为 null");

        // 获取余额、借方金额和贷方金额，如果为 null 则默认为 BigDecimal.ZERO
        BigDecimal balance = gl.getBalance() != null ? gl.getBalance() : BigDecimal.ZERO;
        BigDecimal debitAmount = gl.getDebitAmount() != null ? gl.getDebitAmount() : BigDecimal.ZERO;
        BigDecimal creditAmount = gl.getCreditAmount() != null ? gl.getCreditAmount() : BigDecimal.ZERO;

        // 计算余额
        BigDecimal decimal = balance.add(debitAmount).subtract(creditAmount);
        // 打印调试信息
        System.out.println("decimal:" + decimal);
        return decimal;
    }

    //设置会计期间格式
    private String getPeriodFromVoucherDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月");
        return sdf.format(date);
    }

    //获取前一个会计期间的期末余额
    private BigDecimal getPreviousPeriodClosingBalance(String subjectCode, String period) {
        HashMap<String, String> params = new HashMap<>();
        params.put("subjectCode", subjectCode);
        params.put("period", period);
        System.out.println("Params: " + params);
        return accountBookGeneralMapper.findLastBalanceBySubjectCodeAndBeforePeriod(params);
    }



    /**
     * 修改凭证管理
     *
     * @param accountingVoucher 凭证管理
     * @return 结果
     */
    @Override
    public int updateAccountingVoucher(AccountingVoucher accountingVoucher)
    {
        return accountingVoucherMapper.updateAccountingVoucher(accountingVoucher);
    }

    /**
     * 批量删除凭证管理
     *
     * @param voucherIds 需要删除的凭证管理主键
     * @return 结果
     */
    @Override
    public int deleteAccountingVoucherByVoucherIds(Long[] voucherIds)
    {
        return accountingVoucherMapper.deleteAccountingVoucherByVoucherIds(voucherIds);
    }

    /**
     * 删除凭证管理信息
     *
     * @param voucherId 凭证管理主键
     * @return 结果
     */
    @Override
    public int deleteAccountingVoucherByVoucherId(Long voucherId)
    {
        return accountingVoucherMapper.deleteAccountingVoucherByVoucherId(voucherId);
    }

    @Override
    public int audit(Long id) {
        AccountingVoucher voucher = new AccountingVoucher();
        AccountingVoucher voucher1 = accountingVoucherMapper.selectAccountingVoucherByVoucherId(id);

        voucher.setVoucherId(id);
            voucher.setReviewerId(tokenService.getLoginUser().getUserid());
            if(voucher1.getState() == 0){
                voucher.setState(1L);
            }else {
                voucher.setState(0L);
            }


        return accountingVoucherMapper.updateAccountingVoucher(voucher);
    }

    @Override
    public int importAccountingVouchers(List<AccountingVoucher> voucherList) {
        return accountingVoucherMapper.importAccountingVouchers(voucherList);
    }

    @Override
    public AjaxResult insertAccounting(AccountingVoucher accountingVoucher) {

        // 假设 accountingVoucher 是传入的需要冲销的凭证对象
        AccountingVoucher voucher = accountingVoucherMapper.selectAccountingVoucherByVoucherId(accountingVoucher.getVoucherId());
        AccountingVoucher voucher1 = new AccountingVoucher();

        if (voucher != null) {
            // 获取当前凭证的借贷金额
            BigDecimal creditAmount = accountingVoucher.getCreditAmount();
            BigDecimal debitAmount = accountingVoucher.getDebitAmount();
            // 获取原凭证的借贷金额
            BigDecimal creditAmount1 = voucher.getCreditAmount();
            BigDecimal debitAmount1 = voucher.getDebitAmount();

            // 检查金额是否为 null
            if (creditAmount == null) {
                creditAmount = BigDecimal.ZERO;
            }
            if (debitAmount == null) {
                debitAmount = BigDecimal.ZERO;
            }
            if (creditAmount1 == null) {
                creditAmount1 = BigDecimal.ZERO;
            }
            if (debitAmount1 == null) {
                debitAmount1 = BigDecimal.ZERO;
            }

            // 设置冲销凭证的基本信息
            voucher1.setSummary("冲销:" + accountingVoucher.getSummary());
            voucher1.setVoucherDate(new Date());
            voucher1.setUpdatedAt(new Date());
            voucher1.setVoucherNumber("冲销:" + accountingVoucher.getVoucherNumber());
            voucher1.setStatus(1L);
            voucher1.setAccountId(accountingVoucher.getAccountId());
            voucher1.setPreparerId(accountingVoucher.getPreparerId());

            if (creditAmount.compareTo(creditAmount1) != 0 || debitAmount.compareTo(debitAmount1) != 0) {
                // 金额不同时，直接使用当前凭证的金额
                voucher1.setCreditAmount(creditAmount);
                voucher1.setDebitAmount(debitAmount);
            } else {
                // 金额相同时，将金额取反
                voucher1.setCreditAmount(creditAmount.negate());
                voucher1.setDebitAmount(debitAmount.negate());
            }
        }
        // 检查冲销凭证的借贷金额是否平衡
        if (accountingVoucher.getCreditAmount() != null && accountingVoucher.getDebitAmount() != null) {
            if (accountingVoucher.getCreditAmount().compareTo(accountingVoucher.getDebitAmount()) != 0) {
                return AjaxResult.error("凭证金额不平衡");
            }
        } else {
            return AjaxResult.error("冲销凭证借贷金额存在 null 值");
    }
        // 插入冲销凭证到数据库
        accountingVoucherMapper.insertAccountingVoucher(voucher1);
        return AjaxResult.success("冲销成功");
    }

}
